package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreeTextScan;
import com.heima.aliyun.GreenImageScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.constants.WemediaConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Autowired
    WemediaFeign wemediaFeign;

    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    @Autowired
    GreeTextScan greeTextScan;

    @Autowired
    GreenImageScan greenImageScan;

    @Autowired
    AdChannelMapper adChannelMapper;

    @Autowired
    ArticleFeign articleFeign;


    @Value("${file.oss.web-site}")
    String webSite;


    /**
     * 自媒体文章审核
     *
     * @param wmNewsId
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        // 参数检查
        if (wmNewsId == null) {
            log.error("当前id为空");
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
            return;
        }

        //1、根据文章的id查询自媒体文章
        WmNews wmNews = wemediaFeign.findById(wmNewsId);
        if (wmNews == null) {
            log.info("当前文章为空,自媒体id为 id:{}", wmNewsId);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
            return;
        }
        //2、文章状态=4（人工审核通过） 且发布时间小于等于当前时间 直接保存到文章库
        if (wmNews.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode()) && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            saveAppArticle(wmNews);
            return;
        }

        //3、文章状态=8（文章审核通过，未发布） 且发布时间小于等于当前时间 直接保存到文章库
        if (wmNews.getStatus().equals(WmNews.Status.SUCCESS.getCode()) && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            saveAppArticle(wmNews);
            return;
        }

        //4、文章状态=1 未审核
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            //解析图片和文本内容
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);


            //4.1 自管理敏感词
            Boolean isSensitiveScan = handleSensitive((String) contentAndImagesResult.get("content"), wmNews);
            if (!isSensitiveScan) return;

            //4.2 阿里云-文本内容审核
            Boolean isTextScan = handleTextScan((String) contentAndImagesResult.get("content"), wmNews);
            if (!isTextScan) return;

            //4.3 阿里云-图片审核
            Boolean isImageScan = handleImageScan((List<String>) contentAndImagesResult.get("images"), wmNews);
            if (!isImageScan) return;

            //4.4 如果发布时间大于当前时间 修改wmNews 文章状态=8
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                updateWmNews(wmNews, WmNews.Status.SUCCESS.getCode(), "待发布");
            }
        }


        //5、审核通过 保存文章相关信息（三张表） 修改文章的状态=9 已发布
        saveAppArticle(wmNews);


        //TODO 6、 ES同步索引库
    }


    /**
     * 阿里云文章图片内容审核
     *
     * @param images
     * @param wmNews
     * @return
     */
    private Boolean handleImageScan(List<String> images, WmNews wmNews) {
        Boolean flag = true;

        if (images == null || images.size() == 0) {
            return true;
        }

        try {
            //去重
            images = images.stream()
                    .distinct()
                    .collect(Collectors.toList());


            Map map = greenImageScan.imageUrlScan(images);

            if (map.get("suggestion").equals("block")) {
                flag = false;
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文章中图片违规");
            }
            if (map.get("suggestion").equals("review")) {
                flag = false;
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章中图片疑似违规，需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            log.error("文章审核失败，需要人工审核 id:{}", wmNews.getId());
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章审核失败，需要人工审核");
        }
        return flag;
    }

    /**
     * 阿里云文章文本内容审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private Boolean handleTextScan(String content, WmNews wmNews) {
        Boolean flag = true;

        try {
            Map map = greeTextScan.greeTextScan(content);

            if (map.get("suggestion").equals("block")) {
                flag = false;
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文章中包含敏感词");
            }
            if (map.get("suggestion").equals("review")) {
                flag = false;
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章中疑似敏感词,需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            log.error("文章审核失败，需要人工审核 id:{}", wmNews.getId());
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章审核失败，需要人工审核");
        }

        return flag;
    }

    /**
     * 敏感词自管理
     *
     * @param content
     * @param wmNews
     * @return
     */
    private Boolean handleSensitive(String content, WmNews wmNews) {
        Boolean flag = true;

        //查询敏感词
        List<String> allSensitive = adSensitiveMapper.findAllSensitive();

        //初始化 DFA搜索
        SensitiveWordUtil.initMap(allSensitive);

        //匹配敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);

        if (map.size() > 0) {
            flag = false;
            updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文章中包含了敏感词：" + map);
        }
        return flag;
    }

    /**
     * 更改文章状态并给出理由
     *
     * @param wmNews
     * @param code
     * @param message
     */
    private void updateWmNews(WmNews wmNews, short code, String message) {

        wmNews.setStatus(code);
        wmNews.setReason(message);

        ResponseResult result = wemediaFeign.updateWmNews(wmNews);
        if (!result.getCode().equals(0)) {
            CustException.cust(AppHttpCodeEnum.WEMEDIA_UPDATE_ERROR);
        }


    }


    /**
     * 解析文本和图片内容
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //判断内容的长度是不是超过一万   防止用户非法操作
        if (wmNews.getContent() == null || wmNews.getContent().length() > 10000) {
            return null;
        }

        List<Map> contentList = JSON.parseArray(wmNews.getContent(), Map.class);

        //解析文本内容
        String contents = contentList.stream().filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.joining());

        //解析图片内容
        List<String> images = contentList.stream().filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.toList());

        //处理封面图片前缀
        String imagesCover = wmNews.getImages();
        if (StringUtils.isNotBlank(imagesCover)) {
            images.addAll(
                    Stream.of(imagesCover.split(","))
                            .map(x -> webSite + x)
                            .collect(Collectors.toList())
            );
        }

        //封装结果
        Map<String, Object> map = new HashMap<>();
        map.put("content", contents);
        map.put("images", images);

        return map;
    }

    /**
     * 保存文章到article库
     *
     * @param wmNews
     */
    private void saveAppArticle(WmNews wmNews) {
        //保存文章
        ResponseResult result = saveArticle(wmNews);

        if (!result.getCode().equals(0)) {
            CustException.cust(AppHttpCodeEnum.WEMEDIA_UPDATE_ERROR);
        }

        Object data = result.getData();
        wmNews.setArticleId((Long) data);

        updateWmNews(wmNews, WmNews.Status.PUBLISHED.getCode(), "文章审核通过");
    }


    /**
     * 执行保存文章到三张表中
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        articleDto.setId(null);
        if (wmNews.getArticleId()!=null) {
            articleDto.setId( wmNews.getArticleId() );
        }

        articleDto.setLayout(wmNews.getType());
        articleDto.setFlag((byte) 0);


        if (wmNews.getChannelId()!=null){
            articleDto.setChannelId(wmNews.getChannelId());
            AdChannel channel = adChannelMapper.selectById(wmNews.getChannelId());
            if (channel != null) {
                articleDto.setChannelName(channel.getName());
            }
        }
// 查wm_user 状态
        WmUser wmUser = wemediaFeign.findWmUserById(wmNews.getUserId());
        if (wmUser == null || wmUser.getStatus().intValue() != 9) { // 非法用户
            CustException.cust(AppHttpCodeEnum.ADMIN_ADUSER_ISNTOEXIT_ERROR);
        }
        if (StringUtils.isNotBlank(wmUser.getName())) {
            // 自媒体名称不能修改
            articleDto.setAuthorName(wmUser.getName());
            // 作者id 尽量减少远程调用
        }

        //4 文章内容
        articleDto.setContent(wmNews.getContent());

        // 发起远程调用 保存 三张表数据, 返回值必须携带文章id
        return articleFeign.saveArticle(articleDto);
    }
}
